package com.htjc.integral.account.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.htjc.cht.api.util.AESCoder;
import com.htjc.integral.account.annotation.InvokeLog;
import com.htjc.integral.account.annotation.Signature;
import com.htjc.integral.account.util.SignUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 签名
 * @author hlc
 *
 */
@Slf4j(topic = "jfLog")
@Aspect
@Component
public class SignatureAdvice implements Ordered{
	
	private AESCoder coder=AESCoder.getInstance();
	
	private static String returnMsg;
	
	@Pointcut("execution(public * com.htjc..*.*(..))&&@annotation(signature)")
	public void pointCut(Signature signature) {
	}
	
	@Pointcut("@annotation(invokeLog)")
	public void pointCutInvokeLog(InvokeLog invokeLog) {
	}
	
	//前置通知 打印调用开始并打印请求报文
    @Before("pointCut(signature)&&pointCutInvokeLog(invokeLog)")
    public void doBefore(JoinPoint joinPoint,Signature signature, InvokeLog invokeLog) {
    }
    
    /**
	 * 解密
	 * @param joinPoint
	 * @param fields
	 */
	private boolean decrypt(Object[] args, String[] fields,InvokeLog invokeLog) {
		JSONObject argJson=(JSONObject) JSONObject.parse(args[0].toString());
		for (String field : fields) {
			try {
				Object fieldValue = argJson.get(field);
				if(fieldValue!=null){
					argJson.put(field, coder.decrypt(fieldValue.toString()));
				}
			} catch (Exception e) {
				returnMsg=field+"解密失败";
				return false;
			}
		}
		argJson.remove("SIGN");
		args[0]=argJson.toJSONString();
		argJson.remove("LOG_MSG");
		log.info(invokeLog.decryptArgs(),invokeLog.value(),argJson.toJSONString());
		return true;
	}
	
	/**
	 * 加密 加签
	 * @param proceed
	 * @return
	 *//*
    private JSONObject encrypt(Object proceed,String[] fields,InvokeLog invokeLog){
    	JSONObject resultJson=JSONObject.parseObject(proceed.toString());
    	log.info(invokeLog.encryptArgs(),invokeLog.value(),resultJson.toJSONString());
    	if("0".equals(resultJson.getString("rcode"))){
    		StringBuffer sb=new StringBuffer();
    		JSONObject content = resultJson.getJSONObject("content");
    		for (String field : fields) {
        		try {
        			String fieldValue=content.get(field).toString();
        			content.put(field, coder.encrypt(fieldValue));
        			sb.append(coder.encrypt(fieldValue));
    			} catch (Exception e) {
    				returnMsg=field+"加密失败";
    				return null;
    			}
    		}
    		try {
				content.put("SIGN", SignUtil.sign(sb.toString()));
				resultJson.put("content", content);
			} catch (Exception e) {
				returnMsg="加签失败";
				return null;
			}
    	}
    	return resultJson;
    }*/
	
	@Around("pointCut(signature)&&pointCutInvokeLog(invokeLog)")
	public Object doAround(ProceedingJoinPoint joinPoint,Signature signature,InvokeLog invokeLog) throws Throwable{
		Object[] args = joinPoint.getArgs();
		//1.验签
		if(!verify(args,signature.verifyFields())){
			return logEx(invokeLog);
		}
		//2.解密
		if(!decrypt(args,signature.verifyFields(),invokeLog)){
			return logEx(invokeLog);
		}
		//3.执行方法
		Object proceed = joinPoint.proceed(args);
		//4.加密 加签（返回报文暂时不加密不加签）
		/*JSONObject resultJson = encrypt(proceed, signature.signFields(), invokeLog);
		if(resultJson==null){
			return logEx(invokeLog);
		}
		return resultJson.toString();*/
		return proceed;
	}
	
	private String logEx(InvokeLog invokeLog){
		JSONObject resultJson=new JSONObject();
		resultJson.put("rcode", "-1");
		resultJson.put("message", returnMsg);
		log.error(invokeLog.ex(),invokeLog.value(),returnMsg);
		return resultJson.toString();
	}
	
	/**
	 * 验签
	 * @param joinPoint
	 * @param fields
	 */
	private boolean verify(Object[] args, String[] fields) {
		JSONObject argJson=(JSONObject) JSONObject.parse(args[0].toString());
		StringBuffer buffer = new StringBuffer();
		for (String field : fields) {
			Object fieldValue = argJson.get(field);
			if(fieldValue!=null){
				buffer.append(argJson.get(field).toString());
			}
		}
		String signData=argJson.get("SIGN").toString();
		boolean flag= SignUtil.verify(signData, buffer.toString().getBytes());
		if(!flag){
			returnMsg="验签失败";
		}
		return flag;
	}
	
    @Override  
    public int getOrder() {  
        return 1002;  
    }
}
